package com.gimi.cloud.jimi.dao.mybatis;

import javax.sql.DataSource;

import org.aopalliance.aop.Advice;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;


/**
 * mapper核心类，勿动.
 * Created by luck on 2017/09/28.
 */
@EnableTransactionManagement
@Configuration
public class MyBatisConfig {
    @Autowired
    private DataSource dataSource;

    /**事物相关**/
    private static final int TX_METHOD_TIMEOUT = 5;

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            // 基于注解扫描Mapper，不需配置xml路径 如果需要自定义xml就需要配置
            bean.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"));
            bean.setConfigLocation(resolver.getResource("classpath:/configLocation/mybatis-config.xml"));
            return bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 配置事务管理器
     * 指定JDBC类型事物管理器
     */
    @Bean
    @Primary
    public PlatformTransactionManager transactionManager() throws Exception {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
        return transactionManager;
    }

    /**
     * 添加事物拦截器
     * @return
     * @throws Exception
     */
    @Bean
    public Advice transactionAdvice() throws Exception{
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        /*只读事务，不做更新操作*/
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
        /*当前存在事务就使用当前事务，当前不存在事务就创建一个新的事务*/
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
        requiredTx.setRollbackRules(
                Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        requiredTx.setTimeout(TX_METHOD_TIMEOUT);
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        txMap.put("add*", requiredTx);
        txMap.put("save*", requiredTx);
        txMap.put("insert*", requiredTx);
        txMap.put("update*", requiredTx);
        txMap.put("delete*", requiredTx);
        txMap.put("del*", requiredTx);
        txMap.put("sql*", readOnlyTx);
        txMap.put("select*", readOnlyTx);
        txMap.put("get*", readOnlyTx);
        txMap.put("load*", readOnlyTx);
        txMap.put("query*", readOnlyTx);
        source.setNameMap( txMap );
        TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager(), source);
        return txAdvice;
    }

    /**
     * 添加Advisor
     * @return
     * @throws Exception
     */
    @Bean
    public Advisor transactionAdvisor() throws Exception{
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        //common-service Service目录
        pointcut.setExpression("execution (* com.gimi.cloud.jimi.commonService..*(..))");
        //jimi-manage Service目录
        pointcut.setExpression("execution (* com.gimi.cloud.jimi.manage.service..*(..))");
        //jimi-app Service目录
        pointcut.setExpression("execution (* com.gimi.cloud.jimi.client.service..*(..))");
        //jimi-merchantZone Service目录
        pointcut.setExpression("execution (* com.gimi.cloud.jimi.merchantZone.service..*(..))");
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setAdvice(transactionAdvice());
        advisor.setPointcut(pointcut);
        return advisor;
    }


}
